package com.bzm.service.plugins.impl;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.bzm.common.entity.HttpCode;
import com.bzm.common.entity.JsonResult;
import com.bzm.common.enums.plugins.ImChatMsgTypeEnum;
import com.bzm.common.rabbitmq.FanoutExchangeConfig;
import com.bzm.config.BzmGlobalConfig;
import com.bzm.config.im.UserChannelRel;
import com.bzm.config.redis.RedisConfig;
import com.bzm.mapper.bzm.BzmImChatMsgLogsMapper;
import com.bzm.mapper.bzm.BzmImUserMapper;
import com.bzm.mapper.file.SysFileInfoMapper;
import com.bzm.pojo.bzm.BzmImChatMsgLogs;
import com.bzm.pojo.bzm.BzmImUser;
import com.bzm.pojo.bzm.vo.BzmImChatMsgLogsVo;
import com.bzm.pojo.file.SysFileInfo;
import com.bzm.pojo.plugins.echarts.EchartsCount;
import com.bzm.pojo.plugins.echarts.EchartsOption;
import com.bzm.pojo.plugins.echarts.EchartsSeriesData;
import com.bzm.pojo.plugins.im.ImChatMsg;
import com.bzm.pojo.plugins.im.ImChatUserBind;
import com.bzm.pojo.plugins.im.ImRegisterBeat;
import com.bzm.service.plugins.BzmImCommonService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

import io.netty.channel.Channel;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
	
@Service
public class BzmImCommonServiceImpl implements BzmImCommonService{

	@Autowired
	private RedisTemplate<String, String> redisTemplate;
	@Autowired
	private AmqpTemplate amqpTemplate;
	@Autowired
	private BzmImUserMapper bzmImUserMapper;
	@Autowired
	private BzmGlobalConfig bzmGlobalConfig;
	@Autowired
	private SysFileInfoMapper sysFileInfoMapper;
	@Autowired
	private BzmImChatMsgLogsMapper bzmImChatMsgLogsMapper;
	@Value("${server.port}")
    private String serverPort;
	
	@Override
	public void addImUserAddress(ImChatMsg imChatMsg) {
		String sendId = imChatMsg.getSendId();
		String imLocalAddress = imChatMsg.getImLocalAddress();
		QueryWrapper<BzmImUser> queryWrapper = new QueryWrapper<BzmImUser>();
		queryWrapper.eq("user_id", sendId);
		BzmImUser imUser = bzmImUserMapper.selectOne(queryWrapper);
		// 设置登录时间
		imUser.setLoginTime(LocalDateTime.now());
		bzmImUserMapper.updateById(imUser);
		
		ImChatUserBind userBind = imUser.getToImChatUserBind(imUser);
		// 去掉 斜杠
		userBind.setImLocalAddress(imLocalAddress);
		// 将用户 丢到  缓存
		redisTemplate.opsForValue().set(RedisConfig.im_user_bind_key_redis + sendId,JSON.toJSONString(userBind,SerializerFeature.WriteMapNullValue));
	}

	@Override
	public void sendMsg(ImChatMsg imChatMsg) {
		// 发送者
		String sendId = imChatMsg.getSendId();
		// 接受者 
		String receiveId = imChatMsg.getReceiveId();
		// 判断消息类型
		// 将消息丢到 redis 或者 mq 服务器 , 发布和订阅
		Integer msgType = imChatMsg.getMsgType();
		if(msgType.equals(ImChatMsgTypeEnum.CONNECT.getCode())) {
			
			
			
		}else if(msgType.equals(ImChatMsgTypeEnum.TEXT.getCode())) {
			// 接受者 服务地址
			String userBindJson = redisTemplate.opsForValue().get(RedisConfig.im_user_bind_key_redis+receiveId);
			if(StringUtils.isBlank(userBindJson)) {
				// 离线消息
				
			}
			//ImChatUserBind imChatUserBind = JSON.parseObject(userBindJson, ImChatUserBind.class);
			// 发送mq  
			String mqJsonStr = JSON.toJSONString(imChatMsg);
			Message message = new Message(mqJsonStr.getBytes(), new MessageProperties());
			
			// 保存消息到 db
			BzmImChatMsgLogs logs = new BzmImChatMsgLogs();
			//String msgLogsId = SerialNumberUtils.createNumber("bzm_im", null);
			//logs.setMsgLogsId(msgLogsId);
			logs.getToInitObj(logs,imChatMsg);
			logs.setCreateTime(LocalDateTime.now());
			bzmImChatMsgLogsMapper.insert(logs);
				
			amqpTemplate.convertAndSend(FanoutExchangeConfig.im_chat_fanout_exchange_mq,null, message);
			
			//amqpTemplate.conver
		}else if(msgType.equals(ImChatMsgTypeEnum.IMG.getCode())) {
			
			
			
		}else {
			throw new RuntimeException("未知的消息类型");
		}
	}

	@Override
	public Boolean consumeMsg(ImChatMsg imChatMsg) {
		Integer imType = imChatMsg.getImType();
		// 发送者id
		String sendId = imChatMsg.getSendId();
		// 接受者id
		String receiveId = imChatMsg.getReceiveId();
		if(imType.equals(1)) {
			// 接受者 服务地址
			String userBindJson = redisTemplate.opsForValue().get(RedisConfig.im_user_bind_key_redis+receiveId);
			if(StringUtils.isBlank(userBindJson)) {
				// 离线消息
				
			}else {
				ImChatUserBind userBind = JSON.parseObject(userBindJson, ImChatUserBind.class);
				String imLocalAddress = userBind.getImLocalAddress();
				// 当前服务器  ip 和 端口一致
				String currentLocalAddress = bzmGlobalConfig.getIP()+bzmGlobalConfig.getPort();
				if(imLocalAddress.equals(currentLocalAddress)) {
					Channel channel = UserChannelRel.get(receiveId);
					if(channel!=null) {
						// 离线消息	
						channel.writeAndFlush(
								new TextWebSocketFrame(
										JSON.toJSONString(new JsonResult<ImChatMsg>(imChatMsg, HttpCode.SUCCESS),SerializerFeature.WriteMapNullValue)));
					}
				}
			}
		}
		if(imType.equals(2)) {
			// 群聊消息	
			// String groupId = imChatMsg.getGroupId();
			HashMap<String,Channel> userMap = UserChannelRel.getUserMap();
			for (Entry<String, Channel> map : userMap.entrySet()) {
		         Channel channel = map.getValue();
		         if(channel!=null) {
					channel.writeAndFlush(
							new TextWebSocketFrame(
									JSON.toJSONString(new JsonResult<ImChatMsg>(imChatMsg, HttpCode.SUCCESS),SerializerFeature.WriteMapNullValue)));
				}
	        }	
		}
		return true;
	}
	
	@Override
	public void offLineMsg(String userId) {
		if(StringUtils.isNotBlank(userId)) {
			BzmImUser imUser = new BzmImUser();
			imUser.setUserId(userId);
			imUser.setUpdateTime(LocalDateTime.now());
			imUser.setLoginStatus(2);	
			UpdateWrapper<BzmImUser> updateWrapper = new UpdateWrapper<BzmImUser>();
			updateWrapper.eq("user_id", userId);
			bzmImUserMapper.update(imUser, updateWrapper);
			// 清掉 redis缓存	
			redisTemplate.delete(RedisConfig.im_user_bind_key_redis+userId);
		}
	}

	@Override
	public JsonResult<ImRegisterBeat> selectImRegisterService(String code) {
		Set<String> keys = redisTemplate.keys(RedisConfig.im_service_register_key_redis+"*");
		if(keys.size()>0) {
			String keyVal = "";
		    int min=0;	
			int max=keys.size();
		    Random random = new Random();
		    // 随机数
		    int randomVal = random.nextInt(max)%(max-min+1) + min;
		    Integer count = 0;
			for (String key : keys) {
				if(count.equals(randomVal)) {
					keyVal = key;
					break;
				}
				count++;
			}
			ImRegisterBeat beat = new ImRegisterBeat();
			if(StringUtils.isNotBlank(keyVal)) {
				String keyJson = redisTemplate.opsForValue().get(keyVal);
				if(keyJson!=null) {
					beat = JSON.parseObject(keyJson, ImRegisterBeat.class);
					
				}
			}
			return new JsonResult<ImRegisterBeat>(beat, HttpCode.SUCCESS);
		}
		HttpCode httpCode = HttpCode.PARAM_VERIFICATION;
		httpCode.setMsg("暂无可用的im服务");
		return new JsonResult<ImRegisterBeat>(null, httpCode);
	}

	@Override
	public JsonResult<List<ImRegisterBeat>> selectImRegisterList(String code) {
		List<ImRegisterBeat>  registerList = new ArrayList<ImRegisterBeat>();
		Set<String> keys = redisTemplate.keys(RedisConfig.im_service_register_key_redis+"*");
		if(keys.size()>0) {
			for (String key : keys) {
				String keyJson = redisTemplate.opsForValue().get(key);
				if(keyJson!=null) {
					ImRegisterBeat beat = JSON.parseObject(keyJson, ImRegisterBeat.class);
					registerList.add(beat);
				}
			}
		}
		return new JsonResult<List<ImRegisterBeat>>(registerList, HttpCode.SUCCESS);
	}

	@Override
	public void initImServiceRegister() {
		String ip = bzmGlobalConfig.getIP();
		int port = bzmGlobalConfig.getPort();
		String ipLocalHost = bzmGlobalConfig.getIPLocalHost();
		String serviceAddress = ip+port;
		// 更新 注册中心	
		ImRegisterBeat imRegisterBeat = new ImRegisterBeat();
		imRegisterBeat.setRegisterAddress(serviceAddress);
		imRegisterBeat.setNewBeatTime(LocalDateTime.now());
		imRegisterBeat.setImPort(BzmGlobalConfig.imPort);
		imRegisterBeat.setIp(ipLocalHost);
		imRegisterBeat.setServicePort(port);
		// redisTemplate.opsForValue().set(RedisConfig.im_user_bind_key_redis + sendId,JSON.toJSONString(userBind));
		redisTemplate.opsForValue().set(RedisConfig.im_service_register_key_redis+serviceAddress , JSON.toJSONString(imRegisterBeat,SerializerFeature.WriteMapNullValue),30,TimeUnit.SECONDS);
	}

	@Override
	public JsonResult<List<SysFileInfo>> selectImUserAvatarList(String code) {
		PageHelper.startPage(1, 15);
		QueryWrapper<SysFileInfo> queryWrapper = new QueryWrapper<SysFileInfo>();
		queryWrapper.eq("data_source", code);
		queryWrapper.orderByAsc("file_sort");	
		List<SysFileInfo> list = sysFileInfoMapper.selectList(queryWrapper);
		PageInfo<SysFileInfo> pageInfo = new PageInfo<SysFileInfo>(list);
		if(pageInfo.getSize()>0) {	
			for (SysFileInfo file : list) {
				file.setFileServiceUrl(BzmGlobalConfig.domain_name);
			}
		}
		return new JsonResult<List<SysFileInfo>>(pageInfo.getList(), HttpCode.SUCCESS);
	}

	@Override
	public JsonResult<EchartsOption> selectCountUserAdd(HttpServletRequest request) {
		EchartsOption option = new EchartsOption();
		List<String> xaxisData = new ArrayList<String>();
		List<EchartsSeriesData> seriesList = new ArrayList<EchartsSeriesData>();
		EchartsSeriesData seriesVo = new EchartsSeriesData();
        seriesVo.setSeriesName("新增用户");
		
        List<Integer> seriesData = new ArrayList<Integer>();
        
        LocalDate currentDate = LocalDate.now();
        // 查询近30天的数据	
        LocalDate startTime = currentDate.minusDays(14);
        String startTimeStr = startTime.toString();
        String endTimeStr = currentDate.toString();
        
        // 用户列表
        List<EchartsCount> countList = bzmImUserMapper.selectUserCount(startTimeStr,endTimeStr);
        EchartsCount count = new EchartsCount();
        for (int i = 0; i < 15; i++) {
            String daysStr = startTime.plusDays(i).toString();
            if(countList.size()>0) {
            	EchartsCount newCount = count.getToSumByDate(daysStr,countList,null);
            	seriesData.add(newCount.getSumCounts());
            }else {	
            	 seriesData.add(0);
			}
            xaxisData.add(daysStr);
        }
        seriesVo.setSeriesData(seriesData);
        seriesList.add(seriesVo);		
        option.setXaxisData(xaxisData);
		option.setSeriesList(seriesList);
		return new JsonResult<EchartsOption>(option,HttpCode.SUCCESS);
	}
	

	@Override
	public JsonResult<EchartsOption> selectCountMsgAdd(HttpServletRequest request) {
		EchartsOption option = new EchartsOption();
		List<String> xaxisData = new ArrayList<String>();
		List<EchartsSeriesData> seriesList = new ArrayList<EchartsSeriesData>();
		EchartsSeriesData seriesAll = new EchartsSeriesData();
		seriesAll.setSeriesName("当日总消息");
		
	
        List<Integer> seriesDataAll = new ArrayList<Integer>();        
        LocalDate currentDate = LocalDate.now();
        // 查询近30天的数据	
        LocalDate startTime = currentDate.minusDays(14);
        String startTimeStr = startTime.toString();
        String endTimeStr = currentDate.toString();
        
        // 用户列表
        List<EchartsCount> countList = bzmImChatMsgLogsMapper.selectMsgCount(startTimeStr,endTimeStr);
        EchartsCount count = new EchartsCount();
        for (int i = 0; i < 15; i++) {
            String daysStr = startTime.plusDays(i).toString();
            if(countList.size()>0) {
            	EchartsCount newCount = count.getToSumByDate(daysStr,countList,null);
            	seriesDataAll.add(newCount.getSumCounts());
            }else {	
            	seriesDataAll.add(0);
			}
            xaxisData.add(daysStr);
        }
        seriesAll.setSeriesData(seriesDataAll);
        seriesList.add(seriesAll);		
        
        List<EchartsSeriesData> originSeries = new ArrayList<EchartsSeriesData>();
		EchartsSeriesData seriesOne = new EchartsSeriesData();
		seriesOne.setSeriesName("点对点消息");
		seriesOne.setSeriesId(1);
		originSeries.add(seriesOne);
		
		EchartsSeriesData seriesTwo = new EchartsSeriesData();
		seriesTwo.setSeriesName("群聊消息");
		seriesTwo.setSeriesId(2);
		originSeries.add(seriesTwo);
		for (EchartsSeriesData seriesData : originSeries) {
			Integer seriesId = seriesData.getSeriesId();
			List<Integer> originData = new ArrayList<Integer>();   
			for (int i = 0; i < 15; i++) {
	            String daysStr = startTime.plusDays(i).toString();
	            if(countList.size()>0) {
	            	EchartsCount newCount = count.getToSumByDate(daysStr,countList,seriesId);
	            	originData.add(newCount.getSumCounts());
	            }else {	
	            	originData.add(0);
				}
	        }
			seriesData.setSeriesData(originData);
		}	
		seriesList.addAll(originSeries);
        
        option.setXaxisData(xaxisData);
		option.setSeriesList(seriesList);
		return new JsonResult<EchartsOption>(option,HttpCode.SUCCESS);
	}

	@Override
	public JsonResult<List<BzmImChatMsgLogsVo>> selectGroupMsgList(String groupId) {
		List<BzmImChatMsgLogsVo> list = bzmImChatMsgLogsMapper.selectGroupMsgList(groupId);
		return new JsonResult<List<BzmImChatMsgLogsVo>>(list, HttpCode.SUCCESS);
	}

	@Override
	public JsonResult<List<BzmImChatMsgLogsVo>> selectFriendMsgList(String sendId,String receiveId) {
		List<BzmImChatMsgLogsVo> list = bzmImChatMsgLogsMapper.selectFriendMsgList(sendId,receiveId);
		return new JsonResult<List<BzmImChatMsgLogsVo>>(list, HttpCode.SUCCESS);
	}
	
}
